package io.xccit.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * @author Xccit
 * @Date 2023-01-30
 * @Description 计算器日志功能切面类
 */
@Aspect //切面类
@Component //ioc组件
public class LoggerApsect {
    /**
     * 切入点表达式方法
     */
    @Pointcut("execution(* io.xccit.pojo.impl.CalculatorImpl.*(..))")
    public void pointCut() {
    }

    /**
     * 前置通知方法:
     * Before注解标识此方法为前置通知，execution(* 全类名.方法名(..))为标识在哪个方法中切入
     * *：所有类型的方法(权限修饰符 返回值类型)
     * ..:参数类型列表(int,int)
     * joinPoint:获取方法名及参数列表之类的对象
     * pointCut():切入点表达式重用
     * joinPoint.getSignature():获取对象方法的签名信息
     */
    @Before("pointCut()")
    public void beforeLogger(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        System.out.println("[logger]->前置通知,方法:" + methodName + ",参数:" + Arrays.toString(args));
    }

    /**
     * 后置通知方法
     *
     * @param joinPoint
     */
    @After("pointCut()")
    public void afterLogger(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("[logger]->后置通知,方法:" + methodName);
    }

    /**
     * 返回通知方法
     *
     * @param joinPoint
     * @param result    返回值接收
     * returning：返回值的变量名
     */
    @AfterReturning(value = "pointCut()", returning = "result")
    public void returnLogger(JoinPoint joinPoint, Object result) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("[logger]->返回通知,方法名:" + methodName + ",结果:" + result);
    }

    /**
     * 异常通知方法
     *
     * @param joinPoint
     * @param e         异常信息
     *                  throwing:异常信息变量名
     */
    @AfterThrowing(value = "pointCut()", throwing = "e")
    public void throwingLogger(JoinPoint joinPoint, Throwable e) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("[logger]->异常通知,方法名:" + methodName + ",异常信息:" + e);
    }

    /**
     * 环绕通知方法
     * @param joinPoint 获取目标方法所有信息的对象
     */
    @Around("pointCut()")
    public Object aroundLogger(ProceedingJoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        String methodName = joinPoint.getSignature().getName();
        Object result = null;
        try {
            System.out.println("[logger]->环绕前置通知,方法:" + methodName + ",参数:" + Arrays.toString(args));
            result = joinPoint.proceed();
            System.out.println("[logger]->环绕返回通知,方法名:" + methodName + ",结果:" + result);
        } catch (Throwable e) {
            e.printStackTrace();
            System.out.println("[logger]->环绕异常通知,方法名:"+methodName+",异常信息:"+e);
        }finally {
            System.out.println("[logger]->环绕后置通知,方法:" + methodName);
        }
        return result;
    }
}
